﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SpriteMaker
{
    public partial class BoundWorkingPanel : Control
    {
        private int xCoord, yCoord;
        private int lastMouseX, lastMouseY;
        private Frame activeFrame;
        private BoundGroup activeBoundGroup;
        private Bound activeBound;
        public formMain formInstance;
        private int delta = 2;
        private enum MouseModuleState
        {
            None,
            Drag,
            ResizeLeft,
            ResizeRight,
            ResizeTop,
            ResizeBottom,
            ResizeLeftTop,
            ResizeLeftBottom,
            ResizeRightTop,
            ResizeRightBottom,
        }
        private MouseModuleState mouseState = MouseModuleState.None;
        public BoundWorkingPanel()
        {
            InitializeComponent();
            this.DoubleBuffered = true;
            xCoord = this.ClientSize.Width / 2;
            yCoord = this.ClientSize.Height / 2;
        }

        public void SetActiveFrame(Frame frame)
        {
            activeFrame = frame;
            this.Invalidate();
        }
        public Frame GetActiveFrame()
        {
            return activeFrame;
        }
        public void SetActiveBoundGroup(BoundGroup bg)
        {
            activeBoundGroup = bg;
            this.Invalidate();
        }
        public BoundGroup GetActiveBoundGroup()
        {
            return activeBoundGroup;
        }
        public void SetActiveBound(Bound b)
        {
            activeBound = b;
            this.Invalidate();
        }
        public Bound GetActiveBound()
        {
            return activeBound;
        }
        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            pe.Graphics.Clear(Color.Gray);
            if (activeFrame != null && formInstance.GetImage() != null)
            {
                foreach (FrameModule frameModule in activeFrame.frameModuleList)
                {
                    pe.Graphics.DrawImage(formInstance.GetImage()
                    , new Rectangle(frameModule.x + xCoord, frameModule.y + yCoord, frameModule.module.width, frameModule.module.height)
                        , new Rectangle(frameModule.module.x, frameModule.module.y, frameModule.module.width, frameModule.module.height), GraphicsUnit.Pixel);
                }
            }
            if (activeBoundGroup != null)
            {
                Brush fill = new SolidBrush(Color.FromArgb(80, 0, 255, 0));
                foreach (Bound bound in activeBoundGroup.bounds)
                {
                    switch (bound.GetType())
                    {
                        case Bound.BoundType.Rectangle:
                            pe.Graphics.FillRectangle(fill, ((BoundRectangle)bound).x + xCoord
                                , ((BoundRectangle)bound).y + yCoord, ((BoundRectangle)bound).w, ((BoundRectangle)bound).h);
                            break;
                        case Bound.BoundType.Circle:
                            pe.Graphics.FillEllipse(fill, ((BoundCircle)bound).x - ((BoundCircle)bound).r + xCoord
                                , ((BoundCircle)bound).y - ((BoundCircle)bound).r + yCoord, 2 * ((BoundCircle)bound).r, 2 * ((BoundCircle)bound).r);
                            break;
                    }
                }
            }
            if (activeBound != null)
            {
                Pen pen = new Pen(Color.FromArgb(150, 255, 0, 0));
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                switch (activeBound.GetType())
                {
                    case Bound.BoundType.Rectangle:
                        pe.Graphics.DrawRectangle(pen, ((BoundRectangle)activeBound).x + xCoord
                            , ((BoundRectangle)activeBound).y + yCoord, ((BoundRectangle)activeBound).w, ((BoundRectangle)activeBound).h);
                        break;
                    case Bound.BoundType.Circle:
                        pe.Graphics.DrawEllipse(pen, ((BoundCircle)activeBound).x - ((BoundCircle)activeBound).r + xCoord
                            , ((BoundCircle)activeBound).y - ((BoundCircle)activeBound).r + yCoord, 2 * ((BoundCircle)activeBound).r, 2 * ((BoundCircle)activeBound).r);
                        break;
                }
            }
            Pen line = new Pen(Color.DarkRed);
            line.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
            pe.Graphics.DrawLine(line, new Point(0, Height / 2), new Point(Width, Height / 2));
            pe.Graphics.DrawLine(line, new Point(Width / 2, 0), new Point(Width / 2, Height));
        }

        private void BoundWorkingPanel_Resize(object sender, EventArgs e)
        {
            xCoord = this.ClientSize.Width / 2;
            yCoord = this.ClientSize.Height / 2;
            this.Invalidate();
        }

        private void BoundWorkingPanel_MouseClick(object sender, MouseEventArgs e)
        {

        }

        private void BoundWorkingPanel_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Middle)
            {

            }
            else if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (activeBound != null)
                {
                    switch (activeBound.GetType())
                    {
                        case Bound.BoundType.Rectangle:
                            BoundRectangle boundRect = (BoundRectangle)activeBound;
                            if (Util.PointInRect(e.X, e.Y, boundRect.x + xCoord - delta, boundRect.y + yCoord - delta, boundRect.w + delta, boundRect.h + delta))
                            {
                                if (e.X <= boundRect.x + xCoord + delta && e.Y <= boundRect.y + yCoord + delta)
                                {
                                    mouseState = MouseModuleState.ResizeLeftTop;
                                    this.Cursor = Cursors.SizeNWSE;
                                }
                                else if (e.X <= boundRect.x + xCoord + delta && e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    mouseState = MouseModuleState.ResizeLeftBottom;
                                    this.Cursor = Cursors.SizeNESW;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta && e.Y <= boundRect.y + yCoord + delta)
                                {
                                    mouseState = MouseModuleState.ResizeRightTop;
                                    this.Cursor = Cursors.SizeNESW;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta && e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    mouseState = MouseModuleState.ResizeRightBottom;
                                    this.Cursor = Cursors.SizeNWSE;
                                }
                                else if (e.X <= boundRect.x + xCoord + delta)
                                {
                                    mouseState = MouseModuleState.ResizeLeft;
                                    this.Cursor = Cursors.SizeWE;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta)
                                {
                                    mouseState = MouseModuleState.ResizeRight;
                                    this.Cursor = Cursors.SizeWE;
                                }
                                else if (e.Y <= boundRect.y + yCoord + delta)
                                {
                                    mouseState = MouseModuleState.ResizeTop;
                                    this.Cursor = Cursors.SizeNS;
                                }
                                else if (e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    mouseState = MouseModuleState.ResizeBottom;
                                    this.Cursor = Cursors.SizeNS;
                                }
                                else
                                {
                                    mouseState = MouseModuleState.Drag;
                                    this.Cursor = Cursors.Hand;
                                }
                            }
                            break;
                        case Bound.BoundType.Circle:
                            BoundCircle boundCircle = (BoundCircle)activeBound;
                            if (Util.Distance(e.X, e.Y, boundCircle.x + xCoord, boundCircle.y + yCoord) <= boundCircle.r)
                            {
                                mouseState = MouseModuleState.Drag;
                                this.Cursor = Cursors.Hand;
                            }
                            break;
                    }
                    
                }
            }
            lastMouseX = e.X;
            lastMouseY = e.Y;
        }

        private void BoundWorkingPanel_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left && activeBound != null)
            {
                switch (activeBound.GetType())
                {
                    case Bound.BoundType.Rectangle:
                        BoundRectangle boundRect = (BoundRectangle)activeBound;
                        if (mouseState == MouseModuleState.Drag)
                        {
                            boundRect.x += e.X - lastMouseX;
                            boundRect.y += e.Y - lastMouseY;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeBottom)
                        {
                            boundRect.h = Math.Max(e.Y - yCoord - boundRect.y, 1);
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeLeft)
                        {
                            int newWidth = Math.Max(1, (boundRect.x + boundRect.w + xCoord) - e.X);
                            boundRect.x -= newWidth - boundRect.w;
                            boundRect.w = newWidth;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeLeftBottom)
                        {
                            boundRect.h = Math.Max(e.Y - (boundRect.y + yCoord), 1);
                            int newWidth = Math.Max(1, (boundRect.x + boundRect.w + xCoord) - e.X);
                            boundRect.x -= newWidth - boundRect.w;
                            boundRect.w = newWidth;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeLeftTop)
                        {
                            int newHeight = Math.Max(1, (boundRect.y + boundRect.h + yCoord) - e.Y);
                            boundRect.y -= newHeight - boundRect.h;
                            boundRect.h = newHeight;
                            int newWidth = Math.Max(1, (boundRect.x + boundRect.w + xCoord) - e.X);
                            boundRect.x -= newWidth - boundRect.w;
                            boundRect.w = newWidth;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeRight)
                        {
                            boundRect.w = Math.Max(e.X - (boundRect.x + xCoord), 1);
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeRightBottom)
                        {
                            boundRect.w = Math.Max(e.X - xCoord - boundRect.x, 1);
                            boundRect.h = Math.Max(e.Y - yCoord - boundRect.y, 1);
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeRightTop)
                        {
                            boundRect.w = Math.Max(e.X - (boundRect.x + xCoord), 1);
                            int newHeight = Math.Max(1, (boundRect.y + boundRect.h + yCoord) - e.Y);
                            boundRect.y -= newHeight - boundRect.h;
                            boundRect.h = newHeight;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        else if (mouseState == MouseModuleState.ResizeTop)
                        {
                            int newHeight = Math.Max(1, (boundRect.y + boundRect.h + yCoord) - e.Y);
                            boundRect.y -= newHeight - boundRect.h;
                            boundRect.h = newHeight;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        break;
                    case Bound.BoundType.Circle:
                        BoundCircle boundCircle = (BoundCircle)activeBound;
                        if (mouseState == MouseModuleState.Drag)
                        {
                            boundCircle.x += e.X - lastMouseX;
                            boundCircle.y += e.Y - lastMouseY;
                            this.Refresh();
                            formInstance.UpdateActiveBound();
                        }
                        break;
                }
            }
            else if (e.Button == System.Windows.Forms.MouseButtons.None)
            {
                if (activeBound != null)
                {
                    switch (activeBound.GetType())
                    {
                        case Bound.BoundType.Rectangle:
                            BoundRectangle boundRect = (BoundRectangle)activeBound;
                            if (Util.PointInRect(e.X, e.Y, boundRect.x + xCoord - delta, boundRect.y + yCoord - delta, boundRect.w + delta, boundRect.h + delta))
                            {
                                if (e.X <= boundRect.x + xCoord + delta && e.Y <= boundRect.y + yCoord + delta)
                                {
                                    this.Cursor = Cursors.SizeNWSE;
                                }
                                else if (e.X <= boundRect.x + xCoord + delta && e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    this.Cursor = Cursors.SizeNESW;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta && e.Y <= boundRect.y + yCoord + delta)
                                {
                                    this.Cursor = Cursors.SizeNESW;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta && e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    this.Cursor = Cursors.SizeNWSE;
                                }
                                else if (e.X <= boundRect.x + xCoord + delta)
                                {
                                    this.Cursor = Cursors.SizeWE;
                                }
                                else if (e.X >= boundRect.x + xCoord + boundRect.w - delta)
                                {
                                    this.Cursor = Cursors.SizeWE;
                                }
                                else if (e.Y <= boundRect.y + yCoord + delta)
                                {
                                    this.Cursor = Cursors.SizeNS;
                                }
                                else if (e.Y >= boundRect.y + yCoord + boundRect.h - delta)
                                {
                                    this.Cursor = Cursors.SizeNS;
                                }
                                else
                                {
                                    this.Cursor = Cursors.Hand;
                                }
                            }
                            else if (this.Cursor != Cursors.Default)
                            {
                                this.Cursor = Cursors.Default;
                            }
                            break;
                        case Bound.BoundType.Circle:
                            BoundCircle boundCircle = (BoundCircle)activeBound;
                            if (Util.Distance(e.X, e.Y, boundCircle.x + xCoord, boundCircle.y + yCoord) <= boundCircle.r)
                            {
                                this.Cursor = Cursors.Hand;
                            }
                            else
                            {
                                this.Cursor = Cursors.Default;
                            }
                            break;
                    }
                }
            }
            lastMouseX = e.X;
            lastMouseY = e.Y;
        }

        private void BoundWorkingPanel_MouseUp(object sender, MouseEventArgs e)
        {

        }

        private void BoundWorkingPanel_KeyDown(object sender, KeyEventArgs e)
        {
            KeyProcess(e.KeyCode);
        }
        public void KeyProcess(Keys k)
        {
            if (activeBound != null)
            {
                switch (activeBound.GetType())
                {
                    case Bound.BoundType.Rectangle:
                        BoundRectangle boundRect = (BoundRectangle)activeBound;
                        switch (k)
                        {
                            case Keys.Left:
                                boundRect.x--;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Right:
                                boundRect.x++;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Up:
                                boundRect.y--;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Down:
                                boundRect.y++;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Add:
                                break;
                            case Keys.Subtract:
                                break;
                        }
                        break;
                    case Bound.BoundType.Circle:
                        BoundCircle boundCircle = (BoundCircle)activeBound;
                        switch (k)
                        {
                            case Keys.Left:
                                boundCircle.x--;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Right:
                                boundCircle.x++;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Up:
                                boundCircle.y--;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.Down:
                                boundCircle.y++;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.PageUp:
                            case Keys.Add:
                                boundCircle.r++;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                            case Keys.PageDown:
                            case Keys.Subtract:
                                boundCircle.r--;
                                this.Refresh();
                                formInstance.UpdateActiveBound();
                                break;
                        }
                        break;
                }
            }
        }
    }
}
